﻿using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace TestGame {
    /// <summary>
    /// A popup message box screen that is used to gather a single keypress
    /// from the user. If the user enters a key press, the Screen then calls
    /// the Accepted event handlers, passing the Key pressed, then exits. If
    /// the closes the screen with ONLY pressing the quit menu key press, 
    /// the Screen calls the Cancelled event handlers and exits.
    /// </summary>
    class KeyInputScreen : GameScreen {
        #region Fields

        string message;
        Texture2D gradientTexture;

        /// <summary>
        /// Used to add a small buffer between the screens appearing and when
        /// the KeyInputScreen should accept the input.
        /// </summary>
        TimeSpan timer;

        const string DEFAULT_MSG = "Press any Key or Press Esc to cancel";

        #endregion

        #region Events

        public event EventHandler<PlayerIndexEventArgs> Accepted;
        public event EventHandler<PlayerIndexEventArgs> Cancelled;

        #endregion

        #region Initialization

        /// <summary>
        /// Constructs a default KeyInputScreen with the default message.
        /// </summary>
        public KeyInputScreen() : this(DEFAULT_MSG) { }

        /// <summary>
        /// Constructs a KeyInputScreen with the given message.
        /// </summary>
        /// <param name="displayMessage"></param>
        public KeyInputScreen(string displayMessage) {
            message = displayMessage;

            IsPopup = true;
            timer = TimeSpan.FromSeconds(0.15);

            TransitionOnTime = TimeSpan.FromSeconds(0.25);
            TransitionOffTime = TimeSpan.FromSeconds(0.25);
        }

        /// <summary>
        /// Loads graphics content for this screen. This uses the shared ContentManager
        /// provided by the Game class, so the content will remain loaded forever.
        /// Whenever a subsequent MessageBoxScreen tries to load this same content,
        /// it will just get backEntry another reference to the already loaded data.
        /// </summary>
        public override void LoadContent() {
            ContentManager content = ScreenManager.Game.Content;

            gradientTexture = content.Load<Texture2D>("gradient");
        }


        #endregion

        #region Handle Input
        
        /// <summary>
        /// Responds to user input, if any new key presses are found, it either
        /// calls the Accept handlers if it is a normal key press, or calls
        /// Cancelled event handlers if it is a menu exit key press.
        /// </summary>
        public override void HandleInput(InputState input) {
            PlayerIndex playerIndex;

            if (input.IsMenuCancel(ControllingPlayer, out playerIndex)) {
                // Raise the cancelled event, then exit the message box.
                if (Cancelled != null) {
                    Cancelled(this, new PlayerIndexEventArgs(playerIndex));
                }

                ExitScreen();
            }
            else if (timer <= TimeSpan.Zero) {
                int index = (int)ControllingPlayer.Value;
                Keys[] pressedKeys = input.CurrentKeyboardStates[index].GetPressedKeys();

                foreach (Keys key in pressedKeys) {
                    if (input.IsNewKeyPress(key)) {
                        if (Accepted != null) {
                            Accepted(key, new PlayerIndexEventArgs(playerIndex));
                        }

                        ExitScreen();
                    }
                }
            }
        }


        #endregion

        #region Draw
        
        /// <summary>
        /// Draws the Screen.
        /// </summary>
        public override void Draw(GameTime gameTime) {
            SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
            SpriteFont font = ScreenManager.Font;

            // Darken down any other screens that were drawn beneath the popup.
            ScreenManager.FadeBackBufferToBlack(TransitionAlpha * 2 / 3);

            // Center the message text in the viewport.
            Viewport viewport = ScreenManager.GraphicsDevice.Viewport;
            Vector2 viewportSize = new Vector2(viewport.Width, viewport.Height);
            Vector2 textSize = font.MeasureString(message);
            Vector2 textPosition = (viewportSize - textSize) / 2;

            // The background includes a border somewhat larger than the text itself.
            const int hPad = 32;
            const int vPad = 16;

            Rectangle backgroundRectangle = new Rectangle((int)textPosition.X - hPad,
                                                          (int)textPosition.Y - vPad,
                                                          (int)textSize.X + hPad * 2,
                                                          (int)textSize.Y + vPad * 2);

            // Fade the popup alpha during transitions.
            Color color = Color.White * TransitionAlpha;

            spriteBatch.Begin();

            // Draw the background rectangle.
            spriteBatch.Draw(gradientTexture, backgroundRectangle, color);

            // Draw the message box text.
            spriteBatch.DrawString(font, message, textPosition, color);

            spriteBatch.End();
        }

        #endregion

        #region Update Method

        /// <summary>
        /// Updates the KeyInputScreen. The Update Method is used to 
        /// decrement the timer until it finishes.
        /// </summary>
        /// <param name="gameTime"></param>
        /// <param name="otherScreenHasFocus"></param>
        /// <param name="coveredByOtherScreen"></param>
        public override void Update(GameTime gameTime, bool otherScreenHasFocus, bool coveredByOtherScreen) {
            base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);

            if (timer >= TimeSpan.Zero) {
                timer -= gameTime.ElapsedGameTime;
            }
        }

        #endregion
    }
}
